/*------------------------------------------------------------------------------
$module:      files
$package:     CseApi
$purpose:     register, binary file and filename/path process
$author:      WAYNE WORK STDIO
$CreateAt:    08/07/04
$LastModify:
$license:     Mozilla Public License Version 1.1
------------------------------------------------------------------------------*/

#include "CseApi/platform.h"

#include <windows.h>
#include <winreg.h>

#include "../files.h"
#include "CseApi/CharArray.h"

TCharArray GetCurrExeFileName()
{
    TCharArray ret(_T('\0'),256);
    size_t iLen = GetModuleFileName(0,ret.addr(),256);
    ret.truncate(iLen);
    return ret;
}

TCharArray ChangeFileExt(const TCharArray& sFile, const TCharArray& ext)
{
    TCharArray ret = sFile;

    for (int i = ret.len()-1; i >= 0; i--)
    {
        TXchar ch = ret[i];
        if (ch == _T('.'))
        {
            ret.truncate(i);
            break;
        }
        else if (ch == _T('\\') || ch == _T('/') || ch == _T(':'))
            break;
    }
    ret += ext;
    return ret;
}

TCharArray ExtractFileExt(const TCharArray& FileName)
{
    TCharArray ret;
    for (int i = FileName.len()-1; i >= 0; i--)
    {
        TXchar ch = FileName[i];
        if (ch == _T('.'))
            return ret;
        else if (ch == _T('\\') || ch == _T('/'))
            break;
        else ret = ch + ret;
    }

    ret.clear();
    return ret;
}

TCharArray ExtractFileName(const TCharArray& FileName)
{
    TCharArray ret;
    for (int i = FileName.len()-1; i >= 0; i--)
    {
        TXchar ch = FileName[i];
        if (ch == _T('\\') || ch == _T('/'))
            break;
        else ret = ch + ret;
    }
    return ret;
}

TCharArray ExtractFileDir(const TCharArray& FileName)
{
    TCharArray ret = FileName;
    for (int i = ret.len()-1; i >= 0; i--)
    {
        TXchar ch = FileName[i];
        if (ch == _T('\\') || ch == _T('/'))
        {
            ret.truncate(i);
            break;
        }
    }
    return ret;
}

TBool FileExists(const TXchar *FileName)
{
    WIN32_FIND_DATA FindData;
    HANDLE h = FindFirstFile(FileName, &FindData);

    if (h != INVALID_HANDLE_VALUE)
    {
        FindClose(h);
        return true;
    }
    else return false;
}

TCharArray NormalizeFileName(const TCharArray& sFile)
{
    TCharArray ret = sFile;
    int iLen = ret.len();
    for (int i = 0; i < iLen; i++)
        if (ret[i] == _T('/')) ret[i] = _T('\\');

    TXchar buff[260];
    TXchar *FilePart;
    if (GetFullPathName(ret.addr(),260,buff,&FilePart) > 0)
        return buff;
    else return ret;
}

TBool SearchSubDirs(TCharArray& sOut, const TCharArray& dir)
{
    ASSERT_TRUE(! dir.isEmpty());
    sOut.truncate(0);

    TCharArray TargPath = dir;
    TXchar ch = TargPath[-1];
    if (ch != _T('\\') && ch != _T('/'))
        TargPath += _T("\\");

    TCharArray ToFind = TargPath + _T("*.*");
    WIN32_FIND_DATA FindData;
    HANDLE h = FindFirstFile(ToFind.addr(),&FindData);
    if (INVALID_HANDLE_VALUE == h) return false;

    do
    {
        if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
        {
            TCharArray sCurr = FindData.cFileName;
            if (sCurr != _T(".") && sCurr != _T(".."))
                sOut += TargPath + sCurr + _T('\0');
        }
    }
    while (FindNextFile(h,&FindData));
    FindClose(h);

    return true;
}

TBool GetFileTime(const TCharArray& FileName, TInt64& fTime)
{
    TBool isOk = false;
    HANDLE h = CreateFile(FileName.addr(),GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
    if( h != INVALID_HANDLE_VALUE )
    {
        isOk = GetFileTime(h,NULL,NULL,(FILETIME *)&fTime) != 0;
        CloseHandle(h);
    }
    return isOk;
}

TBool SetFileTime(const TCharArray& FileName, TInt64& fTime)
{
    TBool isOk = false;
    HANDLE h = CreateFile(FileName.addr(),GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
    if( h != INVALID_HANDLE_VALUE )
    {
        isOk = SetFileTime(h,NULL,NULL,(FILETIME *)&fTime) != 0;
        CloseHandle(h);
    }
    return isOk;
}

TUint32 GetFileSize(const TCharArray& FileName)
{
    TUint32 ret = 0;
    HANDLE h = CreateFile(FileName.addr(),GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
    if( h != INVALID_HANDLE_VALUE )
    {
        TUint32 ret = GetFileSize(h,NULL);
        CloseHandle(h);
    }
    return ret;
}

// Following define TDllFile
//==============================================================================
const long HKey_ClassesRoot   = (long) HKEY_CLASSES_ROOT;
const long HKey_CurrentConfig = (long) HKEY_CURRENT_CONFIG;
const long HKey_CurrentUser   = (long) HKEY_CURRENT_USER;
const long HKey_LocalMachine  = (long) HKEY_LOCAL_MACHINE;

TRegConfig::TRegConfig(long root, const TXchar *path)
{
    TCharArray sPath = path;
    CHECK_TRUE(sPath.len() > 0);

    TXchar ch = sPath[0];
    if (ch == _T('\\') || ch == _T('/'))
    {
        sPath.remove(0);
        CHECK_TRUE(sPath.len() > 0);
    }
    int iMax = sPath.len()-1;
    ch = sPath[iMax];
    if (ch == _T('\\') || ch == _T('/'))
    {
        sPath.remove(iMax);
        CHECK_TRUE(sPath.len() > 0);
    }

    m_path        = sPath.transfer(NULL);
    m_hRootKey    = root;
    m_hKey        = 0;
}

TRegConfig::~TRegConfig()
{
    if ( m_hKey != 0 ) close();
    TCharArray s;
    s.transfer(m_path);
}

TBool TRegConfig::close()
{
    if ( m_hKey != 0 )
    {
        if ( RegCloseKey((HKEY) m_hKey) != ERROR_SUCCESS )
        {
            m_hKey = 0;
#ifdef _DEBUG
            LOG_MSG(TCharArray::format(_T("Can not close registry key '%s'"),m_path));
#endif
            return false;
        }
        else m_hKey = 0;
    }
    return true;
}

TBool TRegConfig::open()
{
    if ( m_hKey != 0 )
        return true;

    HKEY tmpKey;
    if (RegOpenKeyEx((HKEY)m_hRootKey,m_path,0,KEY_READ,&tmpKey) != ERROR_SUCCESS)
    {
#ifdef _DEBUG
        LOG_MSG(TCharArray::format(_T("Can not open registry key '%s'"),m_path));
#endif
        return false;
    }

    m_hKey = (long) tmpKey;
    return true;
}

TBool TRegConfig::read(const TXchar *name, TXchar *out)
{
    CHECK_TRUE(name != NULL && name[0] != _T('\0'));

    TBool ret = false;
    if (open())
    {
        LPDWORD pLen = (LPDWORD)((char *)out - sizeof(TUint32));
        if (RegQueryValueEx((HKEY)m_hKey,name,NULL, NULL,(LPBYTE)out,pLen) == ERROR_SUCCESS )
            ret = true;
    }
    return ret;
}

// Following define TDllFile
//==============================================================================
TDllFile::TDllFile(const TXchar *file)
{
    m_handle = loadLib(file);
}

TDllFile::~TDllFile()
{
    unloadLib(m_handle);
}

void *TDllFile::loadLib(const TXchar *file)
{
    void *handle = (void *) LoadLibrary(file);
    CHECK_MSG(NULL != handle, _T("Load dll file error:") + TCharArray(file));
    return handle;
}

void TDllFile::unloadLib(void *handle)
{
    if (NULL != handle)
        FreeLibrary((HMODULE) handle);
}

TBool TDllFile::isLoaded()
{
    return NULL != m_handle;
}

void TDllFile::attach(void * handle)
{
    ASSERT_TRUE(m_handle == NULL);
    m_handle = handle;
}

void *TDllFile::detach()
{
    void *ret = m_handle;
    m_handle = NULL;
    return ret;
}

void *TDllFile::getSymbol(const TXchar *name)
{
    CHECK_TRUE(m_handle != NULL); 
    return (void *) GetProcAddress((HMODULE)m_handle,(LPCSTR)name);
}
